using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using Budgeteer.Services.Common;
using Budgeteer.Services.DataProviders;
using Budgeteer.Services.Domain;

namespace Budgeteer.Services
{
    public class CategoryService
    {
        readonly CategoryDataProvider categoryDataProvider;
        readonly ConfigService config;

        IDictionary<string, string> categoryMasks;

        public CategoryService(CategoryDataProvider categoryDataProvider, ConfigService config)
        {
            this.categoryDataProvider = categoryDataProvider;
            this.config = config;
        }
        
        public string GetChartXmlData(IList<CategoryDto> categories)
        {
            return GetChartXmlData("Spending Categories",categories);
        }

        public string GetChartXmlData(string title, IList<CategoryDto> categories)
        {
            XNamespace vc = "clr-namespace:Visifire.Charts;assembly=Visifire.Charts";
            XDocument doc = new XDocument(
                new XElement(vc + "Chart",
                    new XAttribute(XNamespace.Xmlns + "vc", "clr-namespace:Visifire.Charts;assembly=Visifire.Charts"),
                    new XAttribute("Theme", "Theme3"),
                    new XAttribute("AnimationType", "Type3"),
                    new XElement(vc + "Title",
                        new XAttribute("Text",title)),
                    new XElement(vc + "AxisX",
                        new XAttribute("Title","Categories")),
                    new XElement(vc + "AxisY",
                        new XAttribute("Title","Amount")),
                    new XElement(vc + "DataSeries",
                        new XAttribute("RenderAs","Column"),
                        new XAttribute("LabelEnabled","True"),
                        AddCategoriesXml(vc, categories))
                ));

            return doc.ToString();
        }

        static XElement[] AddCategoriesXml(XNamespace vc, IList<CategoryDto> categories)
        {
            IList<XElement> ret = new List<XElement>();
            foreach (CategoryDto cat in categories)
            {
                ret.Add(new XElement(vc + "DataPoint",
                            new XAttribute("AxisLabel",cat.Name),
                            new XAttribute("YValue",cat.TotalAmount)));
            }
            return ret.ToArray();
        }

        public virtual bool IsDevMode
        {
            get
            {
                return config.GetBoolean("DevMode");
            }
        }

        public IList<CategoryDto> GetCategoriesAmount()
        {
            DateTime startDate = IsDevMode ? config.GetDateTime("StartDate")
                : new DateTime(Time.Now.Year,Time.Now.Month,1);
            DateTime endDate = new DateTime(startDate.Year, startDate.Month, startDate.AddMonths(1).AddDays(-1).Day);
            return categoryDataProvider.GetCategoriesAmount(startDate, endDate);
        }

        public string GetCategoryByChargeDescription(string chargeDescription)
        {
            EnsureCategoryMaskList();

            return GetCategoryByChargeDescription(categoryMasks, chargeDescription);
        }

        private void EnsureCategoryMaskList()
        {
            if(categoryMasks == null)
            {
                categoryMasks = categoryDataProvider.GetAllCategoryMaskPairs();
            }
        }

        public string GetCategoryByChargeDescription(IDictionary<string,string> categoryMasks, string chargeDescription)
        {
            string categoriesPattern = BuildCategoryClasteringRegex(categoryMasks);

            Regex categoriesRegex = new Regex(categoriesPattern,RegexOptions.Compiled);
            Match m = categoriesRegex.Match(chargeDescription);

            string category = null;
             
            if (m.Success && m.Groups.Count > 0)
            {
                for(int i=1;i<m.Groups.Count;i++)
                {
                    if (m.Groups[i].Success)
                    {
                        category = categoriesRegex.GroupNameFromNumber(i);
                        category = category.Replace("_", " ");
                        break;
                    }
                }
            }

            return category;
        }

        public string BuildCategoryClasteringRegex(IDictionary<string,string> categoryMasks)
        {
            StringBuilder sb = new StringBuilder();
            foreach (KeyValuePair<string,string> category in categoryMasks)
            {
                sb.AppendFormat("(?<{0}>{1})|", category.Key.Replace(" ", "_"), category.Value);
            }
            return (sb.Length == 0 ? sb : sb.Remove(sb.Length - 1, 1)).ToString();
        }
    }
}